#pragma  once
#include "headers.h"
#include "UiUtil.h"
#include "Graphic.h"

class WndUtil {
public:
	WndUtil(HWND w = 0);
	virtual ~WndUtil();
public:
	static HWND createWindowEx(DWORD exStyle, LPCTSTR className, LPCTSTR text,
			DWORD style, Rect rect, HWND parent, HMENU menu = 0, LPVOID lParam =
					0);
	static HWND createControl(DWORD exStyle, LPCTSTR className, LPCTSTR text,
			DWORD style, Rect rect, HWND parent, UINT id);
	static HWND getForegroundWindow();
	static HWND getFocusWindow();
public:
	Rect getWindowRect();
	Rect getClientRect();
	Rect getRectByParent();
	BOOL showWindow(int cmdShow);
	BOOL updateWindow();
	HWND setFocus();
	BOOL destroyWindow();
	BOOL moveWindow(int x, int y, int w, int h, BOOL repaint = TRUE);
	void moveToParent(int x, int y);
	void resize(int w, int h);
	void fillParentClientArea();
	BOOL isPopup();
	BOOL isChild();
	BOOL isOverlapped();
	HWND getParent();
	BOOL setMenu(HMENU menu);
	HMENU getMenu();
	//Send WM_CLOSE, not Minimize Window -- API ::CloseWindow(...) will Minimize Window
	void closeWindow();
	HINSTANCE getInstance();
	HRESULT sendMessage(UINT msg, DWORD wParam, DWORD lParam);
	HRESULT postMessage(UINT msg, DWORD wParam, DWORD lParam);
	HRESULT sendMessage(UINT msg);
	HRESULT postMessage(UINT msg);
	void invalidate(bool eraseBackground = false);
	void invalidate(Rect rect, bool eraseBackground = false);
	BOOL isChildForeground();
	bool isForegrouond();
	BOOL isChildFocused();
	bool isFocused();
	Point getCursorPos();

	DWORD getStyle();
	DWORD getExStyle();
	void setStyle(DWORD style);
	void setExStyle(DWORD exStyle);
	void addStyle(DWORD style);
	void removeStyle(DWORD style);
	void addExStyle(DWORD exStyle);
	void removeExStyle(DWORD exStyle);

	void removeAddStyle(DWORD removeStyle, DWORD addStyle);

	void setWindowText(LPCTSTR text);
	WString getWindowText();
	int getWindowTextLength();
	void setVisible(bool visible);
	bool isVisible();

	HWND getFirstChild();
	HWND getFirstSibling();
	HWND getNextSibling();
	HWND getLastSibling();
	HWND getPreSibling();
public:
	HWND getWnd();
	virtual void setWnd(HWND hwnd);
	virtual operator HWND();
private:
	HWND mWnd;
};

inline HWND WndUtil::createWindowEx(DWORD exStyle, LPCTSTR className,
		LPCTSTR text, DWORD style, Rect rect, HWND parent, HMENU menu,
		LPVOID lParam) {
	return CreateWindowEx(exStyle, className, text, style, rect.left, rect.top,
			rect.Width(), rect.Height(), parent, menu, GetModuleHandle(0),
			lParam);
}
inline HWND WndUtil::createControl(DWORD exStyle, LPCTSTR className,
		LPCTSTR text, DWORD style, Rect rect, HWND parent, UINT id) {
	return CreateWindowEx(exStyle, className, text, style, rect.left, rect.top,
			rect.Width(), rect.Height(), parent, HMENU(id), GetModuleHandle(0),
			0);
}
inline WndUtil::WndUtil(HWND w) :
		mWnd(w) {

}
inline HWND WndUtil::getWnd() {
	return mWnd;
}
inline void WndUtil::setWnd(HWND hwnd) {
	mWnd = hwnd;
}

inline WndUtil::operator HWND() {
	return getWnd();
}

inline Rect WndUtil::getWindowRect() {
	Rect r;
	::GetWindowRect(mWnd, &r);
	return r;
}
inline Rect WndUtil::getClientRect() {
	Rect r;
	::GetClientRect(mWnd, &r);
	return r;
}

inline BOOL WndUtil::showWindow(int cmdShow) {
	return ::ShowWindow(mWnd, cmdShow);
}
inline BOOL WndUtil::updateWindow() {
	return ::UpdateWindow(getWnd());
}

inline HWND WndUtil::setFocus() {
	return ::SetFocus(getWnd());
}
inline BOOL WndUtil::destroyWindow() {
	return ::DestroyWindow(getWnd());
}
inline BOOL WndUtil::moveWindow(int x, int y, int w, int h, BOOL repaint) {
	return ::MoveWindow(mWnd, x, y, w, h, repaint);
}
inline HWND WndUtil::getParent() {
	return ::GetParent(getWnd());
}
inline BOOL WndUtil::isPopup() {
	return ::GetWindowLong(mWnd, GWL_STYLE) & WS_POPUP;
}
inline BOOL WndUtil::isChild() {
	return ::GetWindowLong(mWnd, GWL_STYLE) & WS_CHILD;
}
inline BOOL WndUtil::isOverlapped() {
	return ::GetWindowLong(mWnd, GWL_STYLE) & WS_OVERLAPPED;
}

inline void WndUtil::fillParentClientArea() {
	if (isChild()) {
		HWND parent = getParent();
		Rect r;
		::GetClientRect(parent, &r);
		::MoveWindow(mWnd, 0, 0, r.Width(), r.Height(), TRUE);
	}
}

inline BOOL WndUtil::setMenu(HMENU menu) {
	return ::SetMenu(mWnd, menu);
}
inline HMENU WndUtil::getMenu() {
	return ::GetMenu(mWnd);
}
//Send WM_CLOSE, not Minimize Window -- API ::CloseWindow(...) will Minimize Window
inline void WndUtil::closeWindow() {
	sendMessage(WM_CLOSE, 0, 0);
}
inline HINSTANCE WndUtil::getInstance() {
	return GetWindowInstance(mWnd) ;
//	return (HINSTANCE) ::GetWindowLong(mWnd, GWL_HINSTANCE);
}

inline HRESULT WndUtil::sendMessage(UINT msg, DWORD wParam, DWORD lParam) {
	return ::SendMessage(mWnd, msg, wParam, lParam);
}
inline HRESULT WndUtil::postMessage(UINT msg, DWORD wParam, DWORD lParam) {
	return ::PostMessage(mWnd, msg, wParam, lParam);
}
inline HRESULT WndUtil::sendMessage(UINT msg) {
	return ::SendMessage(mWnd, msg, 0, 0);
}
inline HRESULT WndUtil::postMessage(UINT msg) {
	return ::PostMessage(mWnd, msg, 0, 0);
}

inline void WndUtil::invalidate(bool eraseBackground) {
	InvalidateRect(mWnd, 0, eraseBackground);
}
inline void WndUtil::invalidate(Rect rect, bool eraseBackground) {
	InvalidateRect(mWnd, &rect, eraseBackground);
}

inline HWND WndUtil::getForegroundWindow() {
	return GetForegroundWindow();
}
inline bool WndUtil::isForegrouond() {
	return mWnd == GetForegroundWindow();
}
inline BOOL WndUtil::isChildForeground() {
	HWND w = GetForegroundWindow();
//	return IsChild(mWnd, w);
	while (w) {
		HWND p = GetParent(w);
		if (p == mWnd) {
			return true;
		}
		w = p;
	}
	return false;
}

inline HWND WndUtil::getFocusWindow() {
	return GetFocus();
}
inline BOOL WndUtil::isChildFocused() {
	HWND w = GetFocus();
//	return IsChild(mWnd, w);
	while (w) {
		HWND p = GetParent(w);
		if (p == mWnd) {
			return true;
		}
		w = p;
	}
	return false;
}
inline bool WndUtil::isFocused() {
	return mWnd == GetFocus();
}

inline Point WndUtil::getCursorPos() {
	Point pt;
	GetCursorPos(&pt);
	ScreenToClient(mWnd, &pt);
	return pt;
}

inline DWORD WndUtil::getStyle() {
	return GetWindowStyle(mWnd) ;
}
inline DWORD WndUtil::getExStyle() {
	return GetWindowExStyle(mWnd) ;
}
inline void WndUtil::setStyle(DWORD style) {
	SetWindowLong(mWnd, GWL_STYLE, style);
}
inline void WndUtil::setExStyle(DWORD exStyle) {
	SetWindowLong(mWnd, GWL_EXSTYLE, exStyle);
}

inline void WndUtil::addStyle(DWORD style_) {
	DWORD style = getStyle();
	if (!(style & style_)) {
		setStyle(style | style_);
	}
}
inline void WndUtil::addExStyle(DWORD exStyle_) {
	DWORD exstyle = getExStyle();
	if (!(exstyle & exStyle_)) {
		setExStyle(exstyle | exStyle_);
	}
}

inline void WndUtil::removeStyle(DWORD style_) {
	DWORD style = getStyle();
	if (style & style_) {
		setStyle(style & ~style_);
	}
}
inline void WndUtil::removeExStyle(DWORD exStyle_) {
	DWORD exStyle = getExStyle();
	if (exStyle & exStyle_) {
		setStyle(exStyle & ~exStyle_);
	}
}
inline void WndUtil::removeAddStyle(DWORD removeStyle, DWORD addStyle) {
	DWORD style = getStyle();
	if ((style & removeStyle) || (style & (~addStyle))) {
		style &= ~removeStyle;
		style |= addStyle;
		setStyle(style);
	}
}

inline void WndUtil::setWindowText(LPCTSTR text) {
	SetWindowText(mWnd, text);
}
inline WString WndUtil::getWindowText() {
	int len = GetWindowTextLength(mWnd);
	WString ws(len);
	GetWindowText(mWnd, ws.buffer(), len);
	return ws;
}
inline int WndUtil::getWindowTextLength() {
	return GetWindowTextLength(mWnd);
}

inline void WndUtil::setVisible(bool visible) {
	ShowWindow(mWnd, visible ? SW_SHOW : SW_HIDE);
}
inline bool WndUtil::isVisible() {
	return (getStyle() & WS_VISIBLE) != 0;
}

inline HWND WndUtil::getFirstChild() {
	return GetTopWindow(mWnd);
}
inline HWND WndUtil::getFirstSibling() {
	return GetFirstSibling(mWnd);
}
inline HWND WndUtil::getNextSibling() {
	return GetNextSibling(mWnd);
}
inline HWND WndUtil::getLastSibling() {
	return GetLastSibling(mWnd);
}
inline HWND WndUtil::getPreSibling() {
	return GetPrevSibling(mWnd);
}
inline Rect WndUtil::getRectByParent() {
	Rect r = getWindowRect();
	HWND parent = getParent();
	if (parent) {
		Point pt(r.left, r.top);
		ScreenToClient(parent, &pt);
		return Xywh(pt.x, pt.y, r.Width(), r.Height());
	}
	return r;

}
inline void WndUtil::moveToParent(int x, int y) {
	Rect r = getWindowRect();
	MoveWindow(mWnd, x, y, r.Width(), r.Height(), TRUE);
}
inline void WndUtil::resize(int w, int h) {
	Rect r = getRectByParent();
	MoveWindow(mWnd, r.left, r.top, w, h, TRUE);
}

